#include "libutilsconfig.h"
#include "StringUtils.h"
#ifndef	LIB_NO_BOOST
#include <boost/lexical_cast.hpp>
#endif
#if defined(WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#include <algorithm>
#include <sstream>
//#include "lib_localcompile.h"
LIB_NS_BEGIN


#if defined(_UNICODE) || defined(UNICODE)
	typedef  std::wstringstream tstringstream;
#else
	typedef  std::stringstream tstringstream;
#endif
tstring UStrConvUtils::ToString( double val, uint16 precision ,uint16 width ,
	TCHAR fill ,std::ios::fmtflags flags  )
{
	tstringstream stream;
	stream.precision(precision);
	stream.width(width);
	stream.fill(fill);
	if (flags)
		stream.setf(flags);
	stream << val;
	return stream.str();
}

tstring UStrConvUtils::ToString( int32 val, uint16 width ,TCHAR fill ,
	std::ios::fmtflags flags )
{
	tstringstream stream;
	stream.width(width);
	stream.fill(fill);
	if (flags)
		stream.setf(flags);
	stream << val;
	return stream.str();
}

tstring UStrConvUtils::ToString( TCHAR* lpszFormat,... )
{
	va_list args;
	int32 nBuf;
	TCHAR szBuffer[4096];

	va_start(args, lpszFormat);
	nBuf = _vsntprintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), lpszFormat,
		args);
	va_end(args);

	return szBuffer;
}

tstring UStrConvUtils::ToString( bool val, bool YesNo )
{
	if (val)
	{
		return YesNo ? _T("yes") :_T("true");
	}
	else
	{
		return YesNo ? _T("no") : _T("false");
	}
}

tstring UStrConvUtils::ToLower( const tstring& value )
{
	tstring s = value;		
	std::transform(s.begin(), s.end(), s.begin(), tolower);
	return s;
}

tstring UStrConvUtils::ToUpper( const tstring& value )
{
	tstring s = value;
	std::transform(s.begin(), s.end(), s.begin(), toupper);
	return s;
}

double UStrConvUtils::ToDouble( const tstring& val )
{
	return _tstof(val.c_str());
}

int UStrConvUtils::ToInt( const tstring& val )
{
	return _tstoi(val.c_str());
}

bool UStrConvUtils::ToBool( const tstring& value )
{
	tstring s = ToLower(value);
	return ( s== _T("true") || s == _T("yes"));
}

#pragma warning(disable:4333)
std::string UStrConvUtils::WstringToString( const std::wstring& str )
{
	std::string result;
	result.reserve(str.length() * 2);

	for (unsigned int i = 0; i < str.length(); ++i)
	{
		wchar_t wc;
		wc = str[i];

		if (wc < 0x80)
		{
			result += static_cast<char>(wc);
		}
		else if (wc < 0x800)
		{
			result += 0xc0 | (wc>>6);
			result += 0x80 | (wc & 0x3f);
		}
		else if (wc < 0x10000)
		{
			result += 0xe0 | (wc>>12);
			result += 0x80 | ((wc>>6) & 0x3f);
			result += 0x80 | (wc & 0x3f);
		}
		else if (wc < 0x10FFFF)
		{
			result += 0xf0 | (wc>>18);
			result += 0x80 | ((wc>>12) & 0x3f);
			result += 0x80 | ((wc>>6) & 0x3f);
			result += 0x80 | (wc & 0x3f);
		}
		else
		{
			return result; 
		}
	}

	return result;
}

std::wstring UStrConvUtils::StringToWstring( const char* str, int32 length )
{
	std::wstring result;
	result.reserve(length);

	unsigned int len;
	for ( size_t i = 0; i < (size_t)length; i += len)
	{
		unsigned char c = str[i];
		wchar_t wc;
		int minval;

		if (c < 0x80)
		{
			wc = c;
			len = 1;
			minval = 0;
		}
		else if (c < 0xc0) // Lead byte must not be 10xxxxxx
		{
			return result; // Error, not encodable.
		}
		else if (c < 0xe0) // 110xxxxx
		{
			wc = c & 0x1f;
			len = 2;
			minval = 0x80;
		}
		else if (c < 0xf0) // 1110xxxx
		{
			wc = c & 0xf;
			len = 3;
			minval = 0x800;
		}
#if SIZEOF_WCHAR_T >= 4
		else if (c < 0xf8) // 11110xxx
		{
			wc = c & 7;
			len = 4;
			minval = 0x10000;
		}
		else if (c < 0xfc) // 111110xx
		{
			// Length 5 and 6 is declared invalid in Unicode 3.1 and ISO 10646:2003.
			wc = c & 3;
			len = 5;
			minval = 0x110000;
		}
		else if (c < 0xfe) // 1111110x
		{
			// Length 5 and 6 is declared invalid in Unicode 3.1 and ISO 10646:2003.
			wc = c & 1;
			len = 6;
			minval = 0x4000000;
		}
#endif
		else
		{
			return result; // Error, not encodable.
		}

		if (i + len - 1 < (size_t)length)
		{
			for (unsigned int j = 1; j < len; ++j)
			{
				if ((str[i + j] & 0xc0) != 0x80) // All other bytes must be 10xxxxxx
				{
					return result; // Error, not encodable.
				}

				wc <<= 6;
				wc |= str[i + j] & 0x3f;
			}

			if (wc < minval)
			{
				return result; // Error, non-shortest form.
			}
			else
			{
				result += wc;
			}
		}
		else
		{
			return result; // Error, not encodable.
		}
	}

	return result;
}

std::wstring UStrConvUtils::StringToWstring( const std::string& str )
{
	return StringToWstring(str.c_str(),str.size());
}
tstring UStrConvUtils::IPtoString( DWORD dwIp )
{
	BYTE	a = 0, b = 0, c = 0, d = 0;

	a = (BYTE)(dwIp & 0xff);
	b = (BYTE)((dwIp & 0xff00) >> 8);
	c = (BYTE)((dwIp & 0xff0000) >> 16);
	d = (BYTE)((dwIp & 0xff000000) >> 24);	

	tstringstream stream;
	stream<<a<<_T(".")<<b<<_T(".")<<c<<_T(".")<<d;		
	return stream.str();
}

bool UStrUtils::IsNullorEmpty( const TCHAR* data )
{
	return ( data == NULL || _tcslen(data) ==0 ) ? true : false;
}

bool UStrUtils::Contains( const tstring& data,const tstring& tofind )
{
	return (tstring::npos!=data.find(tofind))?true:false;
}

int32 UStrUtils::CompareIgnoreCase( const tstring& data1,const tstring& data2 )
{
	size_t len1 = data1.size();
	size_t len2 = data2.size();
	for(size_t i=0; i<len1,i<len2; ++i)
	{
		if(toupper(data1[i]) - toupper(data2[i]))
			return toupper(data1[i]) - toupper(data2[i]);			
	}
	return len1 - len2;
}

tstring UStrUtils::Trim( const tstring& s,const TCHAR* totrim )
{
	return tstring(s,s.find_first_not_of(totrim),s.find_last_not_of(totrim)+1);
}

tstring UStrUtils::EraseAllChar( const tstring& s,TCHAR key )
{
	TCHAR buff [4096];
	_tcscpy(buff,s.c_str());

	int j=0;
	for (size_t i=0; i < s.size(); ++i)
	{
		if (buff[i] != key)
		{
			buff[j] = buff[i];
			j++;
		}
	}
	buff[j] = '\0';
	return buff;
}

tstring UStrUtils::TrimRight( const tstring& s,const TCHAR* totrim )
{
	return tstring(s,0,s.find_last_not_of(totrim)+1);
}

tstring UStrUtils::TrimRighTCHARSet( const tstring& data,const tstring& charset )
{
	if (!data.size())
	{
		return data;
	}

	TCHAR buff[4096];
	_tcscpy(buff,data.c_str());	

	int index = data.size()-1;
	while (! UStrSetUtils::BelongstoSet(buff[index],charset) )
		index--;
	buff[index+1]='\0';

	return buff;
}

void UStrUtils::Split(tstrings* pdest, const tstring& data, 
	const tstring& delimiter )
{
	int begin = 0;			
	int index = data.find_first_of (delimiter);
	while (index != tstring::npos)
	{
		tstring tmp = data.substr (begin,index-begin);
		pdest->push_back (tmp);
		begin = index+delimiter.size();
		index = data.find_first_of (delimiter,begin);
	}
	if (!data.empty ())
	{
		tstring tmp = data.substr (begin);
		pdest->push_back (tmp);
	}
}

tstring UStrUtils::Replace( const tstring& data, const tstring& searched,
	const tstring& replaced )
{
	tstring ret = data;
	bool islast = false;


	tstring::size_type pos = ret.find(searched);
	if (pos+searched.size() == ret.size())
	{
		islast =true;
	}

	while (pos != std::string::npos)
	{
		ret = ret.replace(pos, searched.size(), replaced);
		if (islast == true)
		{
			ret[pos+replaced.size()+1] = '\0';
			break;
		}

		pos =  pos - searched.size() + replaced.size() + 1;


		pos = ret.find(searched, pos);
		if (pos+searched.size() == (ret.size()-1))
		{
			islast =true;
		}

	}

	return ret;
}

tstring UStrUtils::Replace( const tstring& data, TCHAR searched,
	TCHAR replaced )
{
	TCHAR newser[2],newrep[2];
	newser[0]=searched;
	newser[1] = 0;
	newrep[0] = replaced;
	newrep[1] = 0;
	return Replace(data,newser,newrep);
	
}

tstring UStrUtils::GetDomainFromUrl( const tstring& url )
{
	tstring ret = UStrConvUtils::ToLower(url);
	tstring::size_type pos;		
	TCHAR* protocols[] = {_T("http://"),_T("https://"),_T("ftp://"),_T("file://")};


	for (int i = 0; i < sizeof(protocols)/sizeof(TCHAR*); ++i)
	{
		pos = ret.find (protocols[i]);
		if (pos != tstring::npos)
		{
			ret = ret.substr(pos+ _tcsclen(protocols[i]));
			break;
		}
	}   

	pos = ret.find_first_of (_T("/"));
	if (pos != tstring::npos)
	{
		ret = ret.substr(0,pos);
	}
	return ret;
}

tstring UStrUtils::Join( const tstrings& vec,const tstring& szConnect )
{
	tstringstream stream;

	for (tstrings::const_iterator i = vec.begin(); i != vec.end(); ++i)
	{
		if (i != vec.begin())
			stream << szConnect;

		stream << *i;
	}
	return stream.str();
}

tstring UStrUtils::TrimLefTCHARSet( const tstring& data,const tstring& charset )
{
	if (!data.size())
		return data ;

	TCHAR buff [4096];
	_tcscpy(buff,data.c_str());

	size_t index=0;
	for(index = 0; index < data.size(); ++index)
		if(! UStrSetUtils::BelongstoSet(buff[index],charset) )
			break;

	int i =0;
	while ((buff[i]=buff[index])!='\0')
	{
		i++;
		index++;
	}
	buff[i]='\0';

	return buff;
}

bool UStrUtils::EndsWith( const tstring& data,const tstring& suffix )
{
	if (data.size()<suffix.size())
		return false;
	else
		return data.compare(data.size()-suffix.size(),suffix.size(),suffix) ==0 ;
}

bool UStrUtils::StartsWith( const tstring& data,const tstring& prefix )
{
	return	data.compare(0,prefix.size(),prefix) == 0;
}

bool UStrUtils::IsValidBuffer( const TCHAR* lpsz, int nLength )
{
	if (lpsz == NULL)
		return false;
#ifdef WIN32
	return ::IsBadStringPtr(lpsz, nLength) == 0;
#endif
	return true;
}

tstring UStrUtils::TrimLeft( const tstring& s,const TCHAR* totrim )
{
	return tstring(s,s.find_first_not_of(totrim),s.size());
}

bool UStrSetUtils::BelongstoSet( TCHAR s ,const tstring& charset )
{
	for(size_t i=0; i<charset.size(); ++i)
		if (s != charset[i])
			return false;
	return true;
}

bool UStrSetUtils::IsDigits( const tstring& data )
{
	int len = data.size();
	for (int i=0; i<len; ++i)
		if( (data[i] <'0') || (data[i] >'9') )
			return false;			
	return true;
}

tstring UStrSetUtils::GetWhiteCharSet()
{
	return _T(" \t\n\r\f");
}

void UString::FillChar( TCHAR* pdata,int32 len,TCHAR value )
{
	for (int i=0; i<len-1; i++)
	{
		pdata[i] =value;
	}
}

void UString::FillStart( TCHAR* pdata,const TCHAR* value )
{
	_tcscpy(pdata,value);
}

void UString::FillEnd( TCHAR* pdata,const TCHAR* value )
{
	size_t fulllen = _tcslen(pdata);
	size_t len = _tcslen(value);
	_tcscpy(&pdata[fulllen-len],value);
}

void UString::PadLeft( TCHAR* pdata,int32 len,TCHAR value,int32 num )
{
	len;
	for (int i=0; i<num; ++i)
	{
		pdata[i] = value;
	}
}

void UString::Copy( TCHAR* pdata,const TCHAR* value )
{
	_tcscpy(pdata,value);
}

void UString::Copy( TCHAR* pdata,const tstring& value )
{
	_tcscpy(pdata,value.c_str());
}


bool UString::IsNullorEmpty(TCHAR* pdata)
{
	if(pdata == NULL || _tcslen(pdata) == 0)
		return true;
	else
		return false;
}

LIB_NS_END